<template>
	<view class="comic_reader" :style="{ 'background-color': skinColor.color_bg_1 }"
	@touchstart="touchstart" @touchmove="touchmove" @touchend="touchend" @touchcancel="touchend" :init="init" :change:init="comic.initWatcher">
		<movable-area style="width: 100%;height: 100vh;">
			<movable-view direction="all" inertia scale :damping="40" :friction="1" :scale-min="1" :scale-max="5" style="width: 100%;height: 100vh;">
				<scroll-view class="comic-reader-scroll" style="height: 100vh;" :scroll-into-view="scrollIntoView" scroll-y @scroll="comic.scroll">
					<view style="line-height: 0;">
						<view v-for="(img, i) in currentChapter.content">
							<find-image
							enable-refresh
							show-preview-btn
							class="comic_reader_image"
							:id="'comic_reader_image_' + (i + 1)"
							mode="widthFix" :src="isLoad.indexOf(i) > -1 ? img : ''"
							:referer="currentChapter.referer || ''"
							:decrypt="currentChapter.decrypt || ''"></find-image>
						</view>	
					</view>
				</scroll-view>
			</movable-view>
		</movable-area>
		<view class="position-fixed-cover pointer-none" :style="{
			'visibility': skinMode == 'night' ? 'visible' : 'hidden',
			'background-color': 'rgba(0,0,0,.3)'
		}"></view>
		<view class="position-fixed-cover y-flex y-align-center y-justify-center"
		:style="{
			'background-color': skinColor.color_bg_1,
			'visibility': loading || error ? 'visible' : 'hidden'
		}">
			<com-loading :visible="loading" :color="skinColor.color_1" size="50" v-if="loading"></com-loading>
			<text class="fs-30" :style="{color: skinColor.color_1}" v-if="error">{{error}}</text>
		</view>
		<!-- <view class="comic-reader-center" @tap="controlsShow = true"></view>	 -->
		<view class="position-fixed-cover y-flex" v-show="controlsShow">
			<view class="local-ducment-nav-bar-box" :style="{'background-color': skinColor.color_bg_1}">
				<com-nav-bar :color="skinColor.color_1" status-color="rgba(0,0,0,0)" bg-color="rgba(0,0,0,0)">
					<template #title>
						<com-text lines="2" class="y-flex-1 ml-20 mr-10" weight="bold" line-height="40" size="35"
						:color="skinColor.color_1"
						:value="loading ? '加载中' : (currentChapter.title || (detail.title + '第' + currentChapter.index + '话'))"></com-text>
					</template>
				</com-nav-bar>
			</view>
			<view class="y-flex y-flex-1 position-relative">
				<view class="y-flex-1" @tap="hideControl"></view>
				<view class="y-flex position-absolute right-30 bottom-50" style="z-index: 1;">
					<view class="local-document-btn-circle mt-40" :style="{'background': skinColor.color_bg_1}" @tap="handleRefresh">
						<com-icon name="refresh" size="38" :color="skinColor.color_1"></com-icon>
					</view>
					<view class="local-document-btn-circle mt-40" :style="{'background': skinColor.color_bg_1}" @tap="handleSave">
						<com-icon name="text" size="38" :color="skinColor.color_1"></com-icon>
					</view>
					<view class="local-document-btn-circle mt-40" :style="{'background': skinColor.color_bg_1}" v-if="currentChapter.content">
						<text class="fs-24" :style="{color: skinColor.color_1}">{{start}}/{{currentChapter.content.length}}</text>
					</view>
				</view>
			</view>
			<view class="local-ducment-tabbar-box" :style="{'background-color': skinColor.color_bg_1}">
				<view class="y-flex y-row y-align-center y-justify-between page-padding-gap pt-30 pb-20">
					<view class="y-flex y-align-center" @tap="handleCatalog">
						<com-icon name="sort" :color="skinColor.color_1" size="40"></com-icon>
						<text class="fs-26 y-flex-1 ml-30 mr-30 mt-10" :style="{color: skinColor.color_1}">目录</text>
					</view>
					<view class="y-flex y-align-center" @tap="$store.dispatch('setting/switchSkinMode')">
						<com-icon :name="skinMode == 'night' ? 'creative_fill' : 'creative'" :color="skinColor.color_1" size="40"></com-icon>
						<text class="fs-26 y-flex-1 ml-30 mr-30 mt-10" :style="{color: skinColor.color_1}">{{skinMode == 'night' ? '日间' : '夜间'}}</text>
					</view>
					<view class="y-flex y-align-center" @tap="handlePrev">
						<com-icon name="round_right" style="transform: rotateZ(180deg);" :color="skinColor.color_1" size="40"></com-icon>
						<text class="fs-26 y-flex-1 ml-30 mr-30 mt-10" :style="{color: skinColor.color_1}">上一话</text>
					</view>
					<view class="y-flex y-align-center" @tap="handleNext">
						<com-icon name="round_right" :color="skinColor.color_1" size="40"></com-icon>
						<text class="fs-26 y-flex-1 ml-30 mr-30 mt-10" :style="{color: skinColor.color_1}">下一话</text>
					</view>
				</view>
				<com-safe-bottom></com-safe-bottom>
			</view>
		</view>
		<com-dialog ref="dialog" />
	</view>
</template>

<script>
	import appMixin from '@/assets/mixin/app.js'
	import FindImage from '../components/Image.vue'
	import { openDB, closeDB, insert, select, update } from '@/assets/database'
	export default {
		mixins: [appMixin],
		components: {FindImage},
		computed: {
			history () {
				return this.$store.getters['setting/GET_HISTORY']
			},
			network () {
				return this.$store.getters['network/GET']
			},
			currentChapter () {
				const index = this.chapters.findIndex(c => c.index == (this.current + 1))
				return this.chapters[index] || {}
			},
			saveMessage () {
				return '本次阅读到 第' + (this.current + 1) + '话-第' + this.start + '张图片\n\n是否保存此次阅读位置'
			},
			//点击区域左边位置
			clickLeft () {
				return (this.windowWidth / 2) - (this.touchWidth / 2)
			},
			//点击区域右边位置
			clickRight () {
				return this.clickLeft + this.touchWidth
			},
			//点击区域顶部位置
			clickTop () {
				return (this.windowHeight / 2) - (this.touchHeight / 2)
			},
			//点击区域底部位置
			clickBottom () {
				return this.clickTop + this.touchHeight
			}
		},
		data () {
			return {
				loading: true,//加载
				error: '',//错误提示
				controlsShow: false,
				chapters: [],
				query: {},//路由参数
				context: {},//正文
				detail: {},//详情
				catalog: [],//章节列表
				current: 0,//当前章节定位
				start: 1,//当前第几张图片
				isLoad: [],//图片是否加载集合
				scrollIntoView: '',
				touchWidth: uni.upx2px(200),
				touchHeight: uni.upx2px(200),
				touchstartX: 0,//触摸开始x轴位置
				touchstartY: 0,//触摸开始y轴位置
				touchmoveX: 0,//触摸滑动x轴距离
				touchmoveY: 0,//触摸滑动y轴距离
				touchTime: 0,//触摸时间
				isClick: false,//是否点击到正确位置
				init: -1//通知渲染层初始化完毕
			}
		},
		onReady() {
			this.$native.setFullscreen(true)
			this.catalog = this.$Route.query.chapters
			this.context = this.$Route.query.context
			this.query = this.$Route.query.query || {}
			this.detail = this.$Route.query.detail
			this.current = parseInt(this.$Route.query.current || 0)
			this.start = parseInt(this.$Route.query.start || 1)
			this.initReader(this.current, this.start)
		},
		onUnload() {
			this.$native.setFullscreen(false)
		},
		onShow() {
			uni.$off('find_chapter')
		},
		methods: {
			//初始化阅读
			async initReader (current, start) {
				current = parseInt(current)
				start = parseInt(start)
				try{
					const chapter = await this.getContent(this.catalog[current], current)
					this.isLoad = []
					this.chapters.push(chapter)
					this.loading = false
					this.$nextTick(function () {
						this.scrollIntoView = 'comic_reader_image_' + start
						this.initLoad()
					})
				}catch(e){
					this.loading = false
					this.error = e.toString()
					//TODO handle the exception
				}
			},
			//跳转章节
			async changeReader (current, refresh) {
				try{
					current = parseInt(current)
					const index = this.chapters.findIndex(c => c.index == current + 1)
					if ( index == -1 || refresh ) {
						this.loading = true
						const chapter = await this.getContent(this.catalog[current], current)
						this.chapters.push(chapter)
						this.loading = false
					}
					this.isLoad = []
					this.current = current
					this.scrollIntoView = ''
					this.$nextTick(() => {
						this.scrollIntoView = 'comic_reader_image_1'
						this.initLoad()
					})
				}catch(e){
					this.loading = false
					this.error = e.toString()
					//TODO handle the exception
				}
			},
			//获取漫画内容
			async getContent (chapter, index) {
				let nextUrl, hasNext = true, content = [], title, referer, decrypt
				const request = this.context.request
				const params = Object.assign({}, this.query, this.detail, chapter)
				const staticData = this.context.staticData ? await this.network.staticDataHandle(this.context.staticData, params) : {}
				const dynamicData = this.context.dynamicData || {}
				const newRequest = request ? await this.network.requestHandle(request, params) : null
				while (hasNext) {
				    const response = newRequest ? await this.network.$request(nextUrl ? Object.assign({}, newRequest, {url: nextUrl}) : newRequest) : {}
				    const context = response.data ? await this.network.$list(dynamicData, response.data, response.taskId) : null
				    content = content.concat(context.content)//累积获取内容
					title = context.title || title
					referer = context.referer || referer
					decrypt = context.decrypt || decrypt
				    // 检查是否有下一页
				    nextUrl = newRequest.nextUrl && response.data ? await this.network.$text(newRequest.nextUrl, response.data, response.taskId) : ''
				    hasNext = !!nextUrl
				}
				return Object.assign({}, staticData, {
					index: index + 1,
					title: title || chapter.title || '第' + (index + 1) + '话',
					content: content,
					referer: referer || chapter.referer || this.detail.referer || '',
					decrypt,
					isStart: index == 0,
					isEnd: index == this.catalog.length - 1
				})
			},
			//初始化懒加载
			initLoad () {
				this.init = -1
				this.$nextTick(() => {
					this.init = 1
				})
			},
			//阅读位置改变
			handleChange (current) {
				this.start = current
			},
			//懒加载监听
			handleLazyLoad (indexs) {
				const arr = this.isLoad.concat(indexs)
				this.isLoad = [...new Set(arr)]
			},
			//跳转上一话
			handlePrev () {
				if ( this.current > 0 ) this.changeReader(this.current - 1)
				else uni.showToast({ title: '已经是第一话了', icon: 'none' })
			},
			//跳转下一话
			handleNext () {
				if ( this.current < this.catalog.length - 1 ) this.changeReader(this.current + 1)
				else uni.showToast({ title: '已经是最后一话了', icon: 'none' })
			},
			//查看章节
			handleCatalog () {
				this.$Router.push({
					path: '/pages/find/comic/chapter',
					query: {
						id: this.detail.uniqueId,
						list: this.catalog,
						title: this.detail.title || '',
						type: 'catalog',
						index: this.current,
					},
					animationType: 'slide-in-right',
					complete: () => {
						uni.$once('find_chapter', e => {
							this.$Router.back()
							this.changeReader(e.current)
						})
					}
				})
			},
			async updatePositon () {
				try{
					await openDB()
					const data = await select('record', 'unique_id = "' + this.detail.uniqueId + '"')
					const record = data.list[0] || {}
					if ( record.id ) {
						await update('record', {
							url: this.detail.url,
							title: this.detail.title || '',
							cover: this.detail.cover || '',
							current: this.current,
							position: this.start,
							currentTitle: this.currentChapter.title,
							is_adult: this.detail.isAdult,
							source_id: this.detail.sourceId
						}, 'id = ' + record.id)
					} else {
						await insert('record', {
							unique_id: this.detail.uniqueId,
							url: this.detail.url,
							title: this.detail.title || '',
							cover: this.detail.cover || '',
							current: this.current,
							position: this.start,
							current_title: this.currentChapter.title,
							is_adult: this.detail.isAdult,
							source_id: this.detail.sourceId
						})
					}
				}catch(e){
					uni.showToast({
						title: e.message,
						icon: 'none'
					})
				}
				closeDB()
				return
			},
			handleRefresh () {
				this.changeReader(this.current, true)
			},
			handleSave () {
				this.$refs.dialog.confirm({
					title: '保存提示',
					content: this.saveMessage,
					cancelText: '暂不保存',
					confirmText: '保存记录',
					success: async res => {
						if ( res.confirm ) {
							await this.updatePositon()
							uni.showToast({
								title: '保存成功',
								icon: 'none'
							})
						}
					}
				})
			},
			async handleBack () {
				if ( this.history == 0 ) {
					this.$refs.dialog.confirm({
						title: '退出提示',
						content: this.saveMessage,
						cancelText: '直接退出',
						confirmText: '保存记录',
						success: async res => {
							if ( res.confirm ) {
								await this.updatePositon()
								this.$Router.back()
							} else {
								this.$Router.back()
							}
						}
					})
				} else if ( this.history == 1 ) {
					await this.updatePositon()
					this.$Router.back()
				} else this.$Router.back()
			},
			showControl () {
				this.controlsShow = true
				this.$native.setFullscreen(false)
			},
			hideControl () {
				this.controlsShow = false
				this.$native.setFullscreen(true)
			},
			touchstart (e) {
				if ( this.touchTimer ) {//清楚定时任务
					clearTimeout(this.touchTimer)
					this.touchTimer = null
				}
				const touch = e.touches[0]
				this.touchstartX = touch.pageX
				this.touchstartY = touch.pageY
				//点击在规定区域中
				if ( this.touchstartX >= this.clickLeft && this.touchstartX <= this.clickRight && this.touchstartY >= this.clickTop && this.touchstartY <= this.clickBottom) {
					this.isClick = true
					this.touchTimer = setTimeout(() => {
						this.touchTime = 300
					}, 300)
				} else {//没有点击在规定区域中直接重置触摸事件
					this.resetTouch()
				}
			},
			touchmove (e) {
				if ( !this.isClick ) return
				const touch = e.touches[0]
				this.touchmoveX = Math.abs(touch.pageX - this.touchstartX)
				this.touchmoveY = Math.abs(touch.pageY - this.touchstartY)
			},
			touchend (e) {
				if ( this.touchTimer ) {//清除按下定时任务
					clearTimeout(this.touchTimer);
					this.touchTimer = null
				}
				if ( !this.isClick ) return
				const threshold = 50//移动阙值
				//点击次数为零或者触摸时间超过300，或者滑动距离超过阙值
				if ( this.touchTime >= 300 || this.touchmoveX > threshold || this.touchmoveY > threshold ) {
					this.resetTouch()
					return
				}
				this.showControl()
				this.resetTouch()
			},
			resetTouch () {
				this.touchstartX = 0
				this.touchstartY = 0
				this.touchmoveX = 0
				this.touchmoveY = 0
				this.touchTime = 0
				this.isClick = false
			}
		},
		onBackPress(event) {
			if ( event.from == 'backbutton' ) {
				if ( this.$refs.dialog.modal.show ) {
					this.$refs.dialog.modal.show = false
					return true
				}
				if ( this.controlsShow ) {
					this.hideControl()
					return true
				}
				if ( this.currentChapter && this.currentChapter.content ) {
					this.handleBack()
					return true
				}
			}
			return false
		}
	}
</script>

<!-- #ifdef H5 || APP-VUE -->
<script lang="renderjs" module="comic" type="module">
	export default {
		data () {
			return {
				content: '',
				whole: null,
				windowHeight: 0
			}
		},
		mounted () {
			this.windowHeight = document.body.offsetHeight || window.innerHeight
		},
		methods: {
			//滚动监听实现懒加载图片
			scroll (e) {
				this.lazyLoad(e.detail.scrollTop)
			},
			//初始化懒加载
			initWatcher (newVal) {
				if ( newVal == 1 ) {
					const scrollTop = document.querySelector('.comic-reader-scroll .uni-scroll-view').scrollTop
					this.lazyLoad(scrollTop)
				}
			},
			//懒加载
			lazyLoad (scrollTop) {
				//获取全部图片
				const images = document.querySelectorAll('.comic_reader_image')
				let current = 0, lazyLoads = []
				for ( let i = 0; i < images.length; i++ ) {
					const img = images[i]
					if ( scrollTop >= img.offsetTop ) current = i
					if ( scrollTop + this.windowHeight > img.offsetTop && img.offsetTop + img.offsetHeight > scrollTop) lazyLoads.push(i)
				}
				this.triggerMethod('handleLazyLoad', lazyLoads)//通知图片懒加载
				this.triggerMethod('handleChange', current + 1)
			},
			triggerMethod (name, args) {
				// #ifndef H5
				this.$ownerInstance.callMethod(name, args)
				// #endif
				// #ifdef H5
				this[name](args)
				// #endif
			}
		}
	}
</script>
<!-- #endif -->

<style>
@keyframes local-document-nav-bar-show {
	from {
		transform: translateY(-100%);
	}
	to {
		transform: translateY(0);
	}
}
@keyframes local-document-tabbar-show {
	from {
		transform: translateY(100%);
	}
	to {
		transform: translateY(0);
	}
}
.comic_reader {
	height: 100%;
}
.local-ducment-nav-bar-box {
	box-shadow: 0 0 20px rgba(0,0,0,.2);
	animation: local-document-nav-bar-show .3s both;
}
.local-ducment-tabbar-box{
	box-shadow: -10px 0 20px rgba(0,0,0,.2);
	animation: local-document-tabbar-show .3s both;
}
.local-document-btn-circle {
	width: 100rpx;
	height: 100rpx;
	border-radius: 100rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 0 10px rgba(0,0,0,.2);
}
</style>